<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <script>
    // 1 严格模式
    /* 
       function fn1() {
         // 'use strict'; // 使用严格模式下，this->undefined
         // console.log(this.a); // cannot read properties of undefined (reading 'a')
   
         console.log(this.a);//this-> window
       }
   
       // var a = 2;// window.a = 2; var声明的变量，会自动绑定到window对象上去。
       let a = 2; // let声明的变量，不会绑定到window上。
       fn1();  
    */
    // 2.隐式绑定：当函数引用有上下文对象时，隐式绑定规则会把函数调用中的 this 绑定到这个上下文对象。

    /*     var obj = {
          name: '孟垚',
          look: function () {
            console.log(this); //{name: '孟垚', look: ƒ}
            console.log(this.name);// '孟垚'
          }
        }
        obj.look(); // '孟垚' , 谁调用look(),look方法里面的this就指向谁。
     */
    /* 
        function Person() {
          this.name = '张3'
          this.sayHello = function () {
            console.log(this); // Person {name: '张3', sayHello: ƒ}
            console.log(this.name); // '张3'
          }
        }
    
        new Person().sayHello()

        // 构造函数里面的this,指向实例化对象
     */
    /* 
        function foo() {
          console.log(this); // {a: 42, foo: ƒ}
          console.log(this.a); // 42
        }
    
        var obj2 = {
          a: 42,
          foo: foo
        };
        var obj1 = {
          a: 2,
          obj2: obj2
        }
    
        obj1.obj2.foo() // 42
     */

    // 隐式丢失：
    /*   function foo() {
        console.log(this); // {a: 42, foo: ƒ}
        console.log(this.a); // 42
      }
  
      var obj = {
        a: 2,
        foo,
      }
      // obj.foo()
  
      var bar = obj.foo; // 把foo方法，赋值给bar;  bar是全局的变量。===》 window.bar = obj.foo;
      var a = "hello world" //==> window.a
      bar() // window.bar();
      // foo()
   */
    /* 
        var p1 = {
          name: '张非',
          show: function () {
            let _that = this;
            window.setTimeout(function () {
              console.log(_that); // {name: '张非', show: ƒ}
              console.log(_that.name); //'张非'
              console.log(this); // window
              console.log(this.name); //''
            }, 1000)
          }
        }
    
        p1.show(); */

    // 3. 显示绑定：通过 call、apply、bind 调用函数，this 绑定的是指定的对象。
    /*
     function foo() {
      console.log(this); // {a: 'abc'}
      console.log(this.a); // 'abc'
    }
    var a = 2;
    var obj = {
      a: 'abc'
    }
    foo.call(obj)
    // call (对象，其它参数列表), 在调用call()时，把obj传给this。所以this指向参数obj.
    // 在调用call()时,会把'.'运算符左边的函数里面的代码都执行一次。

    // appley(对象，[参数数组])，只有2个参数，调用apply()时，把参数对象传给foo函数里面的this.
    foo.apply(obj)

    // bind(参数对象), 返回一个修改了this指向的新函数，
    var fn1 = foo.bind(obj)
    fn1(); // {a: 'abc'} // 'abc' 
    */

    // 4. 箭头函数：
    /*  console.log(this); // 当前环境里面的this -> window
     const fn1 = () => {
       console.log(this); // this指向创建箭头函数所在环境的this.
     }
     fn1()// window;
 
     const obj1 = {
       a: 1,
       fn1
     }
     obj1.fn1() // window
 
     function Person() {
       this.sayHi = fn1;
     }
 
     new Person().sayHi() // window; 
     */

    // bind():
    var p1 = {};
    p1.name = 'aaa'
    p1.show = function () {
      console.log(this); // p1 {name: 'aaa', show: ƒ}
      setTimeout(function () {
        console.log(this);// p1 {name: 'aaa', show: ƒ}
      }.bind(this), 1000)
    }
    p1.show(); 
  </script>
</body>

</html>